﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace GISUtil.KML
{
  /// <summary>
  /// Contains methods for serializing and deserializing the XML found in the PolyStyle section of KML
  /// </summary>
  [XmlRoot("PolyStyle")]
  public class PolyStyle : IXmlSerializable
  {
    /// <summary>
    /// The unique Id of this style.
    /// </summary>
    private string id;

    /// <summary>
    /// The Color associated with this style. 
    /// </summary>
    private string color;

    /// <summary>
    /// The Color mode associated with this style.
    /// </summary>
    private ColorMode? colorMode;

    /// <summary>
    /// Whether the polygon should be filled or not. 
    /// </summary>
    private bool? fill;

    /// <summary>
    /// Whether the polygon should be outlined or not. 
    /// </summary>
    private bool? outline;

    /// <summary>
    /// Determines if this class has any styling information associated with it. 
    /// </summary>
    /// <returns>True if at least one of the fields that contains style information has a value, otherwise false.</returns>
    public bool HasAValue()
    {
      return id != null ||
        color != null ||
        colorMode != null ||
        fill != null ||
        outline != null;
    }

    /// <summary>
    /// Does nothing.
    /// </summary>
    /// <returns>Always returns null.</returns>
    public XmlSchema GetSchema()
    {
      return null;
    }

    /// <summary>
    /// Reads the xml in the PolyStyle section of the KML 
    /// </summary>
    /// <param name="reader">Used to read the XML.</param>
    public void ReadXml(XmlReader reader)
    {
      if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "PolyStyle")
      {
        bool isEmptyElement = reader.IsEmptyElement;

        if (!isEmptyElement)
        {
          this.id = reader["Id"];

          XmlReader innerReader = reader.ReadSubtree();

          this.ReadPolystyleXML(innerReader);
        }
      }
    }

    /// <summary>
    /// A helper method for ReadXML
    /// </summary>
    /// <param name="reader">Reads the xml</param>
    public void ReadPolystyleXML(XmlReader reader)
    {
      bool isEmptyElement = false;

      while (reader.Read())
      {
        if (reader.MoveToContent() == XmlNodeType.Element)
        {
          isEmptyElement = reader.IsEmptyElement;

          if (!isEmptyElement)
          {
            if (reader.LocalName == "ColorMode")
            {
              ColorMode val;
              string elementValue = KMLStyle.GetElementStringValue(reader.ReadSubtree());

              if (Enum.TryParse<ColorMode>(elementValue, out val))
              {
                this.colorMode = val;
              }
              else//todo: do we want to do anything with this Error? if we are ignoring it we should just drop the else block
              {
                // Error
              }
            }
            else if (reader.LocalName == "Color")
            {
              this.color = KMLStyle.GetElementStringValue(reader.ReadSubtree());
            }
            else if (reader.LocalName == "fill")
            {
              this.fill = XmlConvert.ToBoolean(KMLStyle.GetElementStringValue(reader.ReadSubtree()));
            }
            else if (reader.LocalName == "outline")
            {
              this.outline = XmlConvert.ToBoolean(KMLStyle.GetElementStringValue(reader.ReadSubtree()));
            }
          }
        }
      }
    }

    /// <summary>
    /// Serializes this class to XML.
    /// </summary>
    /// <param name="writer">Performs the serialization.</param>
    public void WriteXml(XmlWriter writer)
    {
      if (this.id != null)
      {
        writer.WriteAttributeString("Id", this.id);
      }

      if (this.color != null)
      {
        writer.WriteElementString("Color", this.color);
      }

      if (this.colorMode != null)
      {
        writer.WriteElementString("ColorMode", this.colorMode.ToString());
      }

      if (this.fill != null)
      {
        writer.WriteElementString("fill", this.fill.Value ? "1" : "0");
      }

      if (this.outline != null)
      {
        writer.WriteElementString("outline", this.outline.Value ? "1" : "0");
      }
    }
  }
}